﻿using System;
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Printing;
using System.Windows.Forms;
using NGridDrawer.Partitions;
using NGridDrawer.Report;
using NGridDrawer.Report.Layout;

namespace NGridDrawer.Components
{
    /// <summary>this class is able to encapsulate a partition from a grid into a custom report
    /// </summary>
    [ToolboxBitmap(typeof (PrintDocument), "PrintDocument.bmp")]
    public class ReportDrawerComponent : DrawerComponent, IReportDrawer
    {
        private PrintDocument _document;
        private IBlock _footer;

        private Padding _gridPadding;
        private IBlock _header;

        private bool _managePrinting;

        private PrintPageEventHandler _printPageEventHandler;
        private IBlockTitle _title;

        /// <summary>
        /// 	<para>Initializes an instance of the <see cref="ReportDrawerComponent"/> class.</para>
        /// </summary>
        public ReportDrawerComponent()
        {
            initializeInternal();
        }

        /// <summary>
        /// 	<para>Initializes an instance of the <see cref="ReportDrawerComponent"/> class.</para>
        /// </summary>
        /// <param name="container"></param>
        public ReportDrawerComponent(IContainer container) : base(container)
        {
            initializeInternal();
        }



        /// <summary>Get/Set Document Property</summary>
        public PrintDocument Document
        {
            get { return _document; }
            set
            {
                if (_document != value)
                {
                    _document = value;
                    OnPropertyChanged("Document");
                }
            }
        }


        /// <summary>Get/Set ManagePrinting Property</summary>
        public bool ManagePrinting
        {
            get { return _managePrinting; }
            set
            {
                if (_managePrinting != value)
                {
                    if (value && Document == null)
                        throw new InvalidOperationException(
                            "Document property must be set to enable this feature");

                    _managePrinting = value;
                    OnPropertyChanged("ManagePrinting");
                }
            }
        }


        private ReportDrawer reportDrawer { get; set; }

        #region IReportDrawer Members

        /// <summary>Get <see cref="IReportDrawer"/>.Drawer Property</summary>
        [Browsable(false)]
        IPartitionDrawer IReportDrawer.Drawer
        {
            get { return Component.Drawer; }
        }


        /// <summary>Get/Set GridPadding Property</summary>
        public Padding GridPadding
        {
            get { return _gridPadding; }
            set
            {
                if (_gridPadding != value)
                {
                    _gridPadding = value;
                    OnPropertyChanged("GridPadding");
                }
            }
        }


        /// <summary>
        /// Draw all elements of a <see cref="PartitionGrid"/> in a custom report
        /// </summary>
        /// <param name="graphic">graphics used to draw</param>
        /// <param name="clipBounds">Clip area of the report</param>
        /// <returns>
        /// Component has more pages to draw?
        /// </returns>
        public bool Draw(Graphics graphic, RectangleF clipBounds)
        {
            try
            {
                return reportDrawer.Draw(graphic, clipBounds);
            }
            catch (InvalidOperationException ex)
            {
                throw new InvalidOperationException("Report could no be printed", ex);
            }
        }


        /// <summary>Get/Set Footer Property</summary>
        [Browsable(false)]
        public IBlock Footer
        {
            get { return _footer; }
            set
            {
                if (_footer != value)
                {
                    _footer = value;
                    OnPropertyChanged("Footer");
                }
            }
        }


        /// <summary>Get/Set Header Property</summary>
        [Browsable(false)]
        public IBlock Header
        {
            get { return _header; }
            set
            {
                if (_header != value)
                {
                    _header = value;
                    OnPropertyChanged("Header");
                }
            }
        }


        /// <summary>Get/Set Title Property</summary>
        [Browsable(false)]
        public IBlockTitle Title
        {
            get { return _title; }
            set
            {
                if (_title != value)
                {
                    _title = value;
                    OnPropertyChanged("Title");
                }
            }
        }

        #endregion

        private void initializeInternal()
        {
            _printPageEventHandler =
                document_PrintPage;

            PropertyChanged += onPropertyChanged;
        }



        private void document_PrintPage(object sender, PrintPageEventArgs e)
        {
            try
            {
                e.HasMorePages = Draw(e.Graphics, e.MarginBounds);
            }
            catch (InvalidOperationException ex)
            {
                MessageBox.Show(
                    ex.InnerException.Message,
                    ex.Message,
                    MessageBoxButtons.OK,
                    MessageBoxIcon.Exclamation,
                    MessageBoxDefaultButton.Button1,
                    0);

                e.Cancel = true;
            }
        }


        /// <summary>
        /// called when a property have been updated
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void onPropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            if (Equals(sender) && e.PropertyName.Equals("Component")
                || sender.Equals(Component) && e.PropertyName.Equals("Drawer"))
            {
                if (Component == null) reportDrawer = null;
                else if (reportDrawer == null)
                    reportDrawer = new ReportDrawer(Component.Drawer);
                else reportDrawer.Drawer = Component.Drawer;

                if (reportDrawer != null)
                    PropHelper.MovePropertiesTo<IReportDrawer>(this, reportDrawer);
            }


            string propertyName = e.PropertyName;

            if (propertyName.Equals("Document"))
            {
                if (ManagePrinting)
                    ManagePrinting = false;

                if (Document != null)
                    ManagePrinting = true;
            }

            else if (Document != null && propertyName.Equals("ManagePrinting"))
            {
                if (ManagePrinting) //!DesignMode&&
                    Document.PrintPage += _printPageEventHandler;
                else Document.PrintPage -= _printPageEventHandler;
            }

            else if (reportDrawer != null && PropHelper.ContainsProp<IReportDrawer>(this, propertyName))
            {
                PropHelper.CopyProperty<IReportDrawer>(this, reportDrawer, propertyName);
            }
        }

    }
}